import React, {memo, useEffect, useRef, useState} from 'react';
import {useDispatch, useSelector} from "react-redux";
import {Dropdown, Menu, message} from "antd";
import {Link} from "react-router-dom";

import "./protocol.css";
import {ProtocolCanvas} from "../../../common/canvas";
import openCamera from "./images/camera-open.png";
import closeCamera from "./images/camera.png";
import Header from "../../../components/main-header/Header";
import {deepClone, getProtocolChannel} from "../../../common/utils";
import {useDebounce, useSize} from "../../../common/myHooks";
import {saveJump2Run, savePcrAllCycle, savePcrAllRunCycle, saveScanChannel, saveStages} from "./store/actionCreators";
import {
  AMPLIFICATION,
  CANVAS_CONFIG,
  HOLD,
  INFINITE_HOLD,
  MELT,
  MENU_STYLE,
  STAGES_TYPE,
  TEMPERATURE_COLOR_BAR
} from "./config";
import {saveReagentsType} from "../experiment/store/actionCreators";
import {saveNavigationIndex} from "../../../components/navigation/store/actionCreators";
import {saveData} from "../store/actionCreators";
import ExperimentName from "../../../components/experimentName/ExperimentName";
import {LOAD_PROTOCOL} from "../../../common/loadType";
import {saveIsLoad} from "../calculation/components/quantification/store/actionCreators";
import {saveChanneLoad} from "../../setting/channel/store/actionCreators";
import request from "../../../services/request";
import open_CloseLid from './images/open_CloseDoor.png';

export default memo(function Protocol() {
  const dispatch = useDispatch();
  let {
    reduxStages,
    pcrAllCycle,
    reagentsType,
    isReagentsTypeClicked,
    channels,
    data,
    isCN,
    isLoadDone,
    isSave
  } = useSelector(state => ({
    channels: state.protocolReducer.scanChannel,
    reduxStages: state.protocolReducer.stages,
    pcrAllCycle: state.protocolReducer.pcrAllCycle,
    reagentsType: state.experimentReducer.reagentsType,
    isReagentsTypeClicked: state.experimentReducer.isClicked,
    data: state.dataReducer.data,
    isCN: state.languageReducer.isCN,
    isLoadDone: state.calculationReducer.isLoad,
    isSave: state.channelReducer.isSave
  }));
  const protocolCanvasContainer = useRef();  //  获取canvas父元素
  const size = useSize(protocolCanvasContainer, {height: 440, width: 780});  //  获取canvas父元素尺寸(可以响应浏览器窗口改变)
  const [stages, setStages] = useState(() => {
    if (isReagentsTypeClicked) {  //  如果experiment界面重新点击了reagentsType则重新初始化
      switch (reagentsType) {
        case 0:
          dispatch(saveReagentsType(reagentsType, false));
          return [STAGES_TYPE.hold, STAGES_TYPE.amplificationCycle];
        case 1:
          dispatch(saveReagentsType(reagentsType, false));
          return [STAGES_TYPE.hold, STAGES_TYPE.amplificationCycle, STAGES_TYPE.melt];
      }
    } else {
      return reduxStages;
    }
  });  //  根据experiment界面的reagentsType初始化不同的stages
  const [canvasHeight, setCanvasHeight] = useState(440);  //  canvas的高度
  const [temperatureColorBar, setTemperatureColorBar] = useState(TEMPERATURE_COLOR_BAR);  //  Gradient温度条
  const [canvasCount, setCanvasCount] = useState(() => {
    let count = 0;
    stages.forEach(stage => count += stage.steps.length);
    return count;
  }); //  获取计算canvas宽度的基数
  const [temperatureData, setTemperatureData] = useState(stages.map(stage => stage.steps.map(step => step.temperature)).flat()); //  初始化的温度
  const [showSettingTable, setShowSettingTable] = useState(false);  //  显示设置面板
  const [scanChannel, setScanChannel] = useState([]);  //  scanChannel对象
  const [gradientSelected, setGradientSelected] = useState(false);  //  勾选gradient
  const [stepPosition, setStepPosition] = useState({
    stageIndex: 0,
    stepIndex: 0
  }); //  点击齿轮后得到当前step的索引
  const [channel, setChannel] = useState([]);
  const [isChangeLid, setIsChangeLid] = useState(data.hotLidMode);//控制lid
  const [timeIndex, setTimeIndex] = useState(0); //  用来获取每个step中改变了分钟的input还是秒的input,获取它们的id
  const [timeIndex_, setTimeIndex_] = useState(0); //  用来获取每个step中改变了分钟的input还是秒的input,获取它们的id
  // const [dataCopy, setDataCopy] = useState(data);
  let startTemp;  //  获取开始温度
  let endTemp;  //  获取结束温度
  let stepsSum = 0; //  steps总数
  let cloneStages = [];
  let cloneTemperature = [];
  let cloneScanChannel = [];
  let cloneChannel = [];
  let cloneData = {};
  let cloneTemperatureColorBar = [];

  useEffect(() => {
    //TODO:恢复到读setting界面里，待做？
    cloneScanChannel = deepClone(channels, cloneScanChannel);
    let channel;
    cloneScanChannel.forEach(it => {
      it.lists.forEach((item, index) => !item.name && it.lists.splice(index, 1));
      if (it.lists.every(item => !item.isSelected)) {
        it.scan = false;
        it.forbidden = true;
      }
    });
    channel = cloneScanChannel.map(item => item.scan ? 1 : 0);
    let tempChannel = channel;
    // console.log(tempChannel);
    //未load cqa文件时以setting设置为准
    if (isLoadDone || isSave !== -1) {
      //TODO:以大数据里的channels为准
      for (let i = 0; i < cloneScanChannel.length; i++) {
        cloneScanChannel[i].lists.forEach((item, index) => !item.name && cloneScanChannel[i].lists.splice(index, 1));
        cloneScanChannel[i].scan = data.protocol.channels[i] !== 0;
      }
      channel = data.protocol.channels;
      dispatch(saveIsLoad(false));
      dispatch(saveChanneLoad(1));
    }
    setScanChannel(cloneScanChannel);
    setChannel(channel);
    dispatch(saveData({...data, protocol: {...data.protocol, channels: channel}}));
    //当大数据cqa的scanChannel与setting通道设置不一致时，弹出提示
    /* for (let i = 0; i < 6; i++) {
     if (tempChannel[i] === 0 && data.protocol.channels[i] !== 0) {
     return message.warn("Cqa通道模板与Setting不一致，请重新进行Setting通道选择或清除浏览器缓存恢复默认状态！！!",6);
     }
     }*/
  }, []);

  useEffect(() => {
    setCanvasHeight(protocolCanvasContainer.current.clientHeight);
    setIsChangeLid(data.hotLidMode);
    dispatch(saveStages(stages));
    let temperatureLine = ProtocolCanvas.init("protocolCanvas", CANVAS_CONFIG),
      stageSeparationLine = stages.map(item => item.steps.length);  //  stage分割线数组
    temperatureLine.draw(temperatureData);
    temperatureLine.drawStageSeparationLine(stageSeparationLine);
    return () => temperatureLine.destroyCanvas();
  }, [stages, channel, size.height, data.hotLidMode]);  //  stages改变或浏览器窗口改变时重新绘制canvas

  useEffect(() => {
    setTemperatureData(data.protocol.stages.map(stage => stage.steps.map(step => step.temperature)).flat());
    setStages(data.protocol.stages);
    setCanvasCount(data.protocol.stages.reduce((total, cur) => {
      return total + cur.steps.length;
    }, 0));
  }, [data.protocol.stages]);

  useEffect(() => {
    let pcrArr = data.protocol.stages.filter(item => item.state === AMPLIFICATION);
    pcrAllCycle = pcrArr.reduce((preValue, currentValue) => {
      return preValue + currentValue.cycle;
    }, 0);
    dispatch(savePcrAllCycle(pcrAllCycle));
  }, [data.protocol.stages]);

  // if (data.protocol.stages.some(item => item.state === AMPLIFICATION)) {
  //   let amplificationArr = data.protocol.stages.filter(item => item.state === AMPLIFICATION);
  //   amplificationArr.map(item=>{
  //     pcrAllCycle += item.cycle;
  //     // return pcrAllCycle
  //   })
  //   pcrAllCycle = data.protocol.stages.filter(item => item.state === AMPLIFICATION).reduce((preValue, current) => {
  //         return preValue + current.cycle;
  //       }, 0);
  //   dispatch(savePcrAllCycle(pcrAllCycle));

  function dispatchData(stages, channel) {
    dispatch(saveData({
      ...data,
      protocol: {
        name: "protocol",
        stages: stages,
        positions: [1, 1, 1, 1, 1, 1],  //  默认全选,不能更改
        channels: channel,  //  scan Channel选中的为1
        current: {
          state: "",
          cycle: 0,
          pageAllCycle: 0,
          startTemperature: 0,
          endTemperature: 0,
          stepHoldTime: 0,
          pageNum: -1,
          percent: -1,
          stepNum: -1,
          stepTime: -1,
          temperature: -1
        }
      }
    }));
  }

  // 增加Amplification的cycle
  function increaseAmplificationCycle(indey) {
    cloneStages = deepClone(stages, cloneStages);
    cloneStages[indey].cycle < 99 && cloneStages[indey].cycle++;
    setStages(cloneStages);
    dispatchData(cloneStages, channel);
  }

  // 减少Amplification的cycle
  function decreaseAmplificationCycle(indey) {
    cloneStages = deepClone(stages, cloneStages);
    cloneStages[indey].cycle > 2 && cloneStages[indey].cycle--;
    setStages(cloneStages);
    dispatchData(cloneStages, channel);
  }

  // 失去焦点时改变Amplification的cycle
  function changeCycle(cycleSum, indey) {
    cloneStages = deepClone(stages, cloneStages);
    cloneStages[indey].cycle = Number(cycleSum);
    setStages(cloneStages);
    dispatchData(cloneStages, channel);
  }

  // 检查总步数
  function checkStepsSum(stages) {
    stages.forEach(stage => stepsSum += stage.state === AMPLIFICATION ? stage.steps.length + 1 : stage.steps.length);
    if (stepsSum > 25) {
      isCN ?
        message.error("No more than 26 steps can be taken")
        : message.error("不能超过26个步骤");
      return true;
    }
  }

  // 增加Stage
  function addStage(start, stage) {
    cloneStages = deepClone(stages, cloneStages);
    if (checkStepsSum(cloneStages)) { //  判断总步数是否超过26
      return;
    }
    cloneStages.splice(start + 1, 0, stage);
    changeStagesCallBack(cloneStages);
  }

  // 增加一个Hold
  function addHold(indey) {
    addStage(indey, STAGES_TYPE.hold);
  }

  // 增加一个Cycling
  function addCycling(indey) {
    addStage(indey, STAGES_TYPE.amplificationCycle);
  }

  // 增加一个MeltCurve
  function addMeltCurve(indey) {
    cloneStages = deepClone(stages, cloneStages);
    if (cloneStages.some(stage => (stage.state === MELT))) {
      return isCN ? message.error("只可以加一个熔解曲线程序") : message.error("You can only set one Melt");
    }
    addStage(indey, STAGES_TYPE.melt);
  }

  // 增加一个InfiniteHold
  function addInfiniteHold(indey) {
    cloneStages = deepClone(stages, cloneStages);
    if (indey + 1 !== cloneStages.length) {
      return isCN ? message.error("持续保温强制终止") : message.error("Infinite Hold must go to the end");
    }
    addStage(indey, STAGES_TYPE.infiniteHold);
  }

  // 删除一个Stage
  function removeStage(indey) {
    cloneStages = deepClone(stages, cloneStages);
    cloneStages.length > 1 && cloneStages.splice(indey, 1);
    changeStagesCallBack(cloneStages);
  }

  // 增加一个Step
  function addStep(step, indey, indez) {
    cloneStages = deepClone(stages, cloneStages);
    if (checkStepsSum(cloneStages)) { //  判断总步数是否超过26
      return;
    }
    cloneStages[indey].steps.splice(indez + 1, 0, {...step, record: false});
    changeStagesCallBack(cloneStages);
  }

  // 删除一个Step
  function removeStep(indey, indez) {
    cloneStages = deepClone(stages, cloneStages);
    cloneStages[indey].steps.length > 1 && cloneStages[indey].steps.splice(indez, 1);
    changeStagesCallBack(cloneStages);
  }

  // 设置温度
  function setTemperature(value, indey, indez, stage_) {
    if (stage_.state === MELT) {
      if (indez === 0) {  //  melt start 温度
        if (value >= stage_.steps[1].temperature) {
          value = stage_.steps[1].temperature - 0.5;
          message.warn("Melt start must smaller than end.");
        }
      } else if (indez === 1) { //  melt end 温度
        if (value <= stage_.steps[0].temperature) {
          value = stage_.steps[0].temperature + 0.5;
          message.warn("Melt start must smaller than end.");
        }
      }
    }
    cloneStages = deepClone(stages, cloneStages);
    cloneStages[indey].steps[indez].temperature = Number(value);
    setStages(cloneStages);
    cloneTemperature = cloneStages.map(stage => stage.steps.map(step => step.temperature)).flat();
    setTemperatureData(cloneTemperature);
    dispatchData(cloneStages, channel);
  }

  // 设置Melt梯度
  function setGradient(value, indey, indez) {
    cloneStages = deepClone(stages, cloneStages);
    cloneStages[indey].steps[indez].gradient = Number(value);
    setStages(cloneStages);
    dispatchData(cloneStages, channel);
  }

  // 改变相机状态
  function changeRecord(indey, indez) {
    cloneStages = deepClone(stages, cloneStages);
    cloneStages[indey].steps[indez].record = !cloneStages[indey].steps[indez].record;
    cloneStages[indey].steps.forEach((step, index) => (index === indez) || (step.record = false));
    setStages(cloneStages);
    dispatchData(cloneStages, channel);
  }

  // Stages改变时的操作
  function changeStagesCallBack(stages) {
    stepsSum = 0;
    setStages(stages);
    stages.forEach(stage => stepsSum += stage.steps.length);
    cloneTemperature = stages.map(stage => stage.steps.map(step => step.temperature)).flat();
    setCanvasCount(stepsSum);
    setTemperatureData(cloneTemperature);
    dispatchData(stages, channel);
  }

  // 跳转到Run界面
  function jump2Run() {
    dispatch(saveJump2Run(true));
    dispatch(saveNavigationIndex(3)); //  改变redux中的数据重绘导航栏选择run
    sessionStorage.setItem("sessionNavIndex", "3"); //  让导航栏变为Run的选中状态
  }

  // 计算平均温度
  function calcAverageTemperature(startTemp, endTemp) {
    let minUsing = (startTemp / 2) - (endTemp / 2);
    let midTemp = (endTemp / 2) + (startTemp / 2);
    cloneTemperatureColorBar = deepClone(temperatureColorBar, cloneTemperatureColorBar);
    if (startTemp < endTemp) {
      cloneTemperatureColorBar = TEMPERATURE_COLOR_BAR;
    } else if (startTemp > endTemp) {
      cloneTemperatureColorBar = [...TEMPERATURE_COLOR_BAR].reverse();
    }
    cloneTemperatureColorBar[11].value = (midTemp - minUsing).toFixed(1);
    cloneTemperatureColorBar[10].value = (midTemp - minUsing * 0.95).toFixed(1);
    cloneTemperatureColorBar[9].value = (midTemp - minUsing * 0.8).toFixed(1);
    cloneTemperatureColorBar[8].value = (midTemp - minUsing * 0.6).toFixed(1);
    cloneTemperatureColorBar[7].value = (midTemp - minUsing * 0.36).toFixed(1);
    cloneTemperatureColorBar[6].value = (midTemp - minUsing * 0.12).toFixed(1);
    cloneTemperatureColorBar[5].value = (midTemp + minUsing * 0.12).toFixed(1);
    cloneTemperatureColorBar[4].value = (midTemp + minUsing * 0.36).toFixed(1);
    cloneTemperatureColorBar[3].value = (midTemp + minUsing * 0.6).toFixed(1);
    cloneTemperatureColorBar[2].value = (midTemp + minUsing * 0.8).toFixed(1);
    cloneTemperatureColorBar[1].value = (midTemp + minUsing * 0.95).toFixed(1);
    cloneTemperatureColorBar[0].value = (midTemp + minUsing).toFixed(1);
    console.log(cloneTemperatureColorBar);
    setTemperatureColorBar(cloneTemperatureColorBar);
  }

  // 显示设置面板
  function setAdvancedSetting(step, indey, indez) {
    setShowSettingTable(true);
    setGradientSelected(stages[indey].steps[indez].gradientDeltaTemperature.checked);
    setStepPosition({
      stageIndex: indey,
      stepIndex: indez
    });
    calcAverageTemperature(stages[indey].steps[indez].gradientDeltaTemperature.start, stages[indey].steps[indez].gradientDeltaTemperature.end);
  }

  // 勾选Gradient
  function selectSettingGradient() {
    cloneStages = deepClone(stages, cloneStages);
    cloneStages[stepPosition.stageIndex].steps[stepPosition.stepIndex].gradientDeltaTemperature.checked =
      !cloneStages[stepPosition.stageIndex].steps[stepPosition.stepIndex].gradientDeltaTemperature.checked;
    setGradientSelected(!gradientSelected);
    setStages(cloneStages);
    dispatchData(cloneStages, channel);
  }

  // 勾选染料
  function selectScanChannel(item, indey) {
    console.log(scanChannel);
    if (item.forbidden) {
      return message.warn("The channel has all been closed");
    }
    cloneScanChannel = deepClone(scanChannel, cloneScanChannel);
    cloneChannel = deepClone(channel, cloneChannel);
    cloneChannel[indey] = Number(!item.scan);
    cloneScanChannel[indey].scan = !item.scan;
    dispatch(saveScanChannel(cloneScanChannel));
    setScanChannel(cloneScanChannel);
    setChannel(cloneChannel);
    dispatchData(stages, cloneChannel);
    dispatch(saveScanChannel(cloneScanChannel));
  }

  // 选择染料
  function chooseScanChannel(item, indey) {
    cloneScanChannel = deepClone(scanChannel, cloneScanChannel);
    cloneScanChannel[indey].showName = item.name;
    dispatch(saveScanChannel(cloneScanChannel));
    setScanChannel(cloneScanChannel);
    dispatch(saveScanChannel(cloneScanChannel));
  }

  // 修改Gradient温度
  function changeGradientTemperature(startTemp, endTemp) {
    let start = Number(startTemp);
    let end = Number(endTemp);
    cloneStages = deepClone(stages, cloneStages);
    let result = [stages[stepPosition.stageIndex].steps[stepPosition.stepIndex].gradientDeltaTemperature.start,
      stages[stepPosition.stageIndex].steps[stepPosition.stepIndex].gradientDeltaTemperature.end];

    if (start < 0 || start > 99.9 || end < 0 || end > 99.9) {
      return result;
    } else if ((start - end) >= 1 && (Math.abs(start - end)) <= 30) {
      cloneStages[stepPosition.stageIndex].steps[stepPosition.stepIndex].gradientDeltaTemperature.start = start;
      cloneStages[stepPosition.stageIndex].steps[stepPosition.stepIndex].gradientDeltaTemperature.end = end;
      cloneStages[stepPosition.stageIndex].steps[stepPosition.stepIndex].temperature = (start + end) / 2;
      cloneTemperature = cloneStages.map(stage => stage.steps.map(step => step.temperature)).flat();
      calcAverageTemperature(start, end);
      setStages(cloneStages);
      dispatchData(cloneStages, channel);
      setTemperatureData(cloneTemperature);
      return [start, end];
    } else if ((end - start) >= 1 && (Math.abs(start - end)) <= 30) {
      cloneStages[stepPosition.stageIndex].steps[stepPosition.stepIndex].gradientDeltaTemperature.start = start;
      cloneStages[stepPosition.stageIndex].steps[stepPosition.stepIndex].gradientDeltaTemperature.end = end;
      cloneStages[stepPosition.stageIndex].steps[stepPosition.stepIndex].temperature = (start + end) / 2;
      cloneTemperature = cloneStages.map(stage => stage.steps.map(step => step.temperature)).flat();
      calcAverageTemperature(start, end);
      setStages(cloneStages);
      dispatchData(cloneStages, channel);
      setTemperatureData(cloneTemperature);
      return [start, end];
    } else {
      return result;
    }
  }

  // 选择PauseAfter
  function selectPauseAfter() {
    cloneStages = deepClone(stages, cloneStages);
    cloneStages[stepPosition.stageIndex].steps[stepPosition.stepIndex].autoDelta.checkAutoPauseAfter =
      !cloneStages[stepPosition.stageIndex].steps[stepPosition.stepIndex].autoDelta.checkAutoPauseAfter;
    setStages(cloneStages);
    dispatchData(cloneStages, channel);
  }

  // 选择DeltaTemperature
  function selectDeltaTemperature() {
    cloneStages = deepClone(stages, cloneStages);
    cloneStages[stepPosition.stageIndex].steps[stepPosition.stepIndex].autoDelta.checkAutoDeltaTemperature =
      !cloneStages[stepPosition.stageIndex].steps[stepPosition.stepIndex].autoDelta.checkAutoDeltaTemperature;
    setStages(cloneStages);
    dispatchData(cloneStages, channel);
  }

  // 选择DeltaTime
  function selectDeltaTime() {
    cloneStages = deepClone(stages, cloneStages);
    cloneStages[stepPosition.stageIndex].steps[stepPosition.stepIndex].autoDelta.checkAutoDeltaTime =
      !cloneStages[stepPosition.stageIndex].steps[stepPosition.stepIndex].autoDelta.checkAutoDeltaTime;
    setStages(cloneStages);
    dispatchData(cloneStages, channel);
  }

  // 选择RampRate
  function selectRampRate() {
    cloneStages = deepClone(stages, cloneStages);
    cloneStages[stepPosition.stageIndex].steps[stepPosition.stepIndex].autoDelta.checkRampRate =
      !cloneStages[stepPosition.stageIndex].steps[stepPosition.stepIndex].autoDelta.checkRampRate;
    setStages(cloneStages);
    dispatchData(cloneStages, channel);
  }

  // 修改DeltaTemperature
  function changeDeltaTemperature(value) {
    cloneStages = deepClone(stages, cloneStages);
    cloneStages[stepPosition.stageIndex].steps[stepPosition.stepIndex].autoDelta.autoDeltaTemperature = Number(value);
    setStages(cloneStages);
    dispatchData(cloneStages, channel);
  }

  // 修改DeltaTime
  function changeDeltaTime(value) {
    cloneStages = deepClone(stages, cloneStages);
    cloneStages[stepPosition.stageIndex].steps[stepPosition.stepIndex].autoDelta.autoDeltaTime = Number(value);
    setStages(cloneStages);
    dispatchData(cloneStages, channel);
  }

  // 修改RampRate
  function changeRampRate(value) {
    cloneStages = deepClone(stages, cloneStages);
    cloneStages[stepPosition.stageIndex].steps[stepPosition.stepIndex].autoDelta.rampRate = Number(value);
    setStages(cloneStages);
    dispatchData(cloneStages, channel);
  }

  // 为全局data对象设置CoverTemp
  function setCoverTemp(value) {
    dispatch(saveData({...data, coverTemp: Number(value)}));
  }

  // 为全局data对象设置ReactionVolume
  function setReactionVolume(value) {
    dispatch(saveData({...data, reactionVolume: Number(value)}));
  }

  // 事件委托改变时间
  function changeTime(e) {
    let minute, second;
    if (e.target.previousSibling) {
      if (!Number(e.target.previousSibling.previousSibling.value) && !Number(e.target.value)) {
        e.target.value = "01";
        minute = 0;
        second = 1;
      } else {
        e.target.value = Math.min(Number(e.target.value), 99);
        e.target.value = e.target.value.padStart(2, "0");
        second = e.target.value;
        minute = e.target.previousSibling.previousSibling.value;
      }
    } else if (e.target.nextSibling) {
      if (!Number(e.target.nextSibling.nextSibling.value) && !Number(e.target.value)) {
        e.target.nextSibling.nextSibling.value = "01";
        minute = 0;
        second = 1;
      } else {
        e.target.value = Math.min(Number(e.target.value), 99);
        e.target.value = e.target.value.padStart(2, "0");
        minute = e.target.value;
        second = e.target.nextSibling.nextSibling.value;
      }
    }
    cloneStages = deepClone(stages, cloneStages);
    cloneStages[timeIndex].steps[timeIndex_].time = Number(minute) * 60 + Number(second);
    setStages(cloneStages);
    dispatchData(cloneStages, channel);
  }


  //控制热盖的开关
  /*  function changeLidTemp() {
   cloneData = deepClone(data, cloneData);
   // if (cloneData.connectPort === '') {
   //   message.warn(isCN ? "尚未连接仪器!" : "The instrument has not been connected!");
   //   return;
   // }
   cloneData.hotLidMode = !cloneData.hotLidMode;
   setIsChangeLid(cloneData.hotLidMode);
   dispatch(saveData(cloneData));
   console.log(cloneData);
   // request({
   //   url: "/deviceAction/changeLidTemp",
   //   data: cloneData,
   //   method: "post"
   // }).then(res => {
   //   switch (res.code) {
   //     case 200:
   //       break;
   //     case 500:
   //       message.info("Experiments are in progress, disable change");
   //   }
   // })
   //   .catch(err => message.error(err));
   }*/

  const changeLidTemp = debounce(() => {
    cloneData = deepClone(data, cloneData);
    cloneData.hotLidMode = !cloneData.hotLidMode;
    setIsChangeLid(cloneData.hotLidMode);
    dispatch(saveData(cloneData));
    console.log(cloneData);
  }, 5000, true);

  /**
   * 防抖函数，返回函数连续调用时，空闲时间必须大于或等于 wait，func 才会执行
   *
   * @param  {function} func        回调函数
   * @param  {number}   wait        表示时间窗口的间隔
   * @param  {boolean}  immediate   设置为ture时，是否立即调用函数
   * @return {function}             返回客户调用函数
   */
  function debounce(func, wait = 50, immediate = true) {
    let timer, context, args;

    // 延迟执行函数
    const later = () => setTimeout(() => {
      // 延迟函数执行完毕，清空缓存的定时器序号
      timer = null;
      // 延迟执行的情况下，函数会在延迟函数中执行
      // 使用到之前缓存的参数和上下文
      if (!immediate) {
        func.apply(context, args);
        context = args = null;
      }
    }, wait);

    // 这里返回的函数是每次实际调用的函数
    return function (...params) {
      // 如果没有创建延迟执行函数（later），就创建一个
      if (!timer) {
        timer = later();
        // 如果是立即执行，调用函数
        // 否则缓存参数和调用上下文
        if (immediate) {
          func.apply(this, params);
        } else {
          context = this;
          args = params;
        }
        // 如果已有延迟执行函数（later），调用的时候清除原来的并重新设定一个
        // 这样做延迟函数会重新计时
      } else {
        clearTimeout(timer);
        timer = later();
      }
    };
  }

  //Protocol Edit组件汉化 key value
  let cnMap = new Map([
    ['Hold', '保温'],
    ['Amplification', 'PCR扩增'],
    ['Melt', '熔解曲线'],
    ['Infinite Hold', '持续保温']
  ]);

  return (
    <div>
      <Header name={isCN ? "程序设置" : "Protocol Edit"}
              imgPosition="-50px"
              isSave={true}
              isLoad={true}
              loadType={LOAD_PROTOCOL}
      />
      <section className="mainSection protocolPage">
        <ExperimentName/>
        <div className="protocolPagePart0">
          <div>
            <div/>
            <p>100</p>
            <p>80</p>
            <p>60</p>
            <p>40</p>
            <p>20</p>
            <div/>
          </div>
          <div className="scrollBarStyle">
            <section className="protocolPagePart0Header">
              {
                stages.map((stage, index) => (
                  <div key={index}>
                    {
                      <div style={{
                        width: index === 0
                          ? `${240 + (stage.steps.length - 1) * 260}px`
                          : `${220 + (stage.steps.length - 1) * 260}px`
                      }}
                      >
                        {
                          stage.state === AMPLIFICATION
                            ? <div>
                              <p>{isCN ? cnMap.get(stage.state) : stage.state}</p>
                              <p key={stage.cycle}>
                                <input type="number" defaultValue={stage.cycle}
                                       onBlur={e => {
                                         e.target.value = Math.max(2, e.target.value);
                                         e.target.value = Math.min(99, e.target.value);
                                         changeCycle(e.target.value, index);
                                       }}
                                /> {isCN ? "循环" : "Cycle"}
                              </p>
                              <p onClick={() => increaseAmplificationCycle(index)}/>
                              <p onClick={() => decreaseAmplificationCycle(index)}/>
                            </div>
                            : <div>
                              <p>{isCN ? cnMap.get(stage.state) : stage.state}</p>
                              {/*<p>{`${stage.cycle} Cycle`}</p>*/}
                              <p>{stage.cycle} {isCN ? "循环" : "Cycle"}</p>
                            </div>
                        }
                      </div>
                    }
                    <div>
                      {
                        stage.state === INFINITE_HOLD
                          ? null
                          : <Dropdown
                            overlay={
                              stage.state === MELT
                                ? <Menu>
                                  <Menu.Item key="3">
                                    <div onClick={() => addInfiniteHold(index)}
                                         style={MENU_STYLE}>{isCN ? "持续保温" : "Infinite Hold"}
                                    </div>
                                  </Menu.Item>
                                </Menu>
                                : <Menu>
                                  <Menu.Item key="0">
                                    <div onClick={() => addHold(index)}
                                         style={MENU_STYLE}>{isCN ? "保温" : "Hold"}
                                    </div>
                                  </Menu.Item>
                                  <Menu.Item key="1">
                                    <div onClick={() => addCycling(index)}
                                         style={MENU_STYLE}>{isCN ? "PCR扩增" : "Amplification"}
                                    </div>
                                  </Menu.Item>
                                  <Menu.Item key="2">
                                    <div onClick={() => addMeltCurve(index)}
                                         style={MENU_STYLE}>{isCN ? "熔解曲线" : "Melt Curve"}
                                    </div>
                                  </Menu.Item>
                                  <Menu.Item key="3">
                                    <div onClick={() => addInfiniteHold(index)}
                                         style={MENU_STYLE}>{isCN ? "持续保温" : "Infinite Hold"}
                                    </div>
                                  </Menu.Item>
                                </Menu>
                            }
                            trigger={['click']}>
                            <div className="ant-dropdown-link"
                                 onClick={e => e.preventDefault()}>+
                            </div>
                          </Dropdown>
                      }
                      <div style={{top: "50px", lineHeight: "23px"}}
                           onClick={() => removeStage(index)}>-
                      </div>
                    </div>
                  </div>
                ))
              }
            </section>
            <section style={{width: canvasCount * 260}} id="protocolCanvas" ref={protocolCanvasContainer}
                     className="protocolPagePart0Canvas"/>
            <section className="protocolPagePart0Main">
              {
                stages.map((stage, index) => (
                  stage.steps.map((step, index_) => (
                    <div key={index_} onBlur={e => changeTime(e)}>
                      <p style={{bottom: (10 + (canvasHeight - 10) / CANVAS_CONFIG.maxY * step.temperature) - 9}}>
                        <span>
                          {
                            step.gradientDeltaTemperature.checked
                              ? <input key={step.gradientDeltaTemperature} type="text"
                                       value={`${step.gradientDeltaTemperature.start}-${step.gradientDeltaTemperature.end}`}
                                       readOnly={true}
                              />
                              : <input key={step.temperature} type="number"
                                       defaultValue={step.temperature.toFixed(2)}
                                       onBlur={e => {
                                         e.stopPropagation();
                                         e.target.value = Math.min(99.9, e.target.value);
                                         e.target.value = Math.max(0, e.target.value);
                                         e.target.value = Number(e.target.value).toFixed(2);
                                         setTemperature(e.target.value, index, index_, stage);
                                       }}
                              />
                          }
                        </span>
                        <span>℃</span>
                      </p>
                      {
                        stage.state === MELT
                          ? null
                          : <p style={{bottom: (10 + (canvasHeight - 10) / CANVAS_CONFIG.maxY * step.temperature) - 40}}>
                            <input type="number"
                                   key={"minute_" + (index + index_ + step.time)}
                                   id={"minute_" + (index + index_)}
                                   defaultValue={String(Math.floor(step.time / 60)).padStart(2, "0")}
                                   onFocus={() => {
                                     setTimeIndex(index);
                                     setTimeIndex_(index_);
                                   }}
                            />
                            <span>:</span>
                            <input type="number"
                                   key={"second_" + (index + index_ + step.time)}
                                   id={"second_" + (index + index_)}
                                   defaultValue={String(step.time % 60).padStart(2, "0")}
                                   onFocus={() => {
                                     setTimeIndex(index);
                                     setTimeIndex_(index_);
                                   }}
                            />
                          </p>
                      }
                      {
                        stage.state === MELT && index_ === 0
                          ?
                          <p
                            style={{bottom: (10 + (canvasHeight - 10) / CANVAS_CONFIG.maxY * ((stages[index].steps[index_ + 1].temperature + step.temperature) / 2)) - 9}}
                            className="protocolMeltInput"
                          >
                            <input key={step.gradient} type="number"
                                   defaultValue={step.gradient.toFixed(2)}
                                   onBlur={e => {
                                     e.stopPropagation();
                                     e.target.value = Math.min(1, e.target.value);
                                     e.target.value = Math.max(0.1, e.target.value);
                                     e.target.value = Number(e.target.value).toFixed(2);
                                     setGradient(e.target.value, index, index_);
                                   }}
                            />
                            <span>℃</span>
                          </p>
                          : null
                      }
                    </div>
                  ))
                ))
              }
            </section>
            <section className="protocolPagePart0Footer">
              {
                stages.map((stage, index) => (
                  stage.state === MELT
                    ? stage.steps.map((step, index_) => (
                      <div key={index_}>
                        {
                          index_ === 1
                            ? <div
                              style={{backgroundImage: step.record ? `url(${openCamera})` : `url(${closeCamera})`}}
                              className="protocolCamera"
                              onClick={() => changeRecord(index, index_)}
                            />
                            : null
                        }
                      </div>
                    ))
                    : stage.steps.map((step, index_) => (
                      <div key={index_}>
                        {
                          stage.state === INFINITE_HOLD
                            ? null
                            : <div
                              style={{backgroundImage: step.record ? `url(${openCamera})` : `url(${closeCamera})`}}
                              className="protocolCamera"
                              onClick={() => changeRecord(index, index_)}
                            />
                        }
                        <div className="protocolSetting"
                             onClick={() => setAdvancedSetting(step, index, index_)}/>
                        {
                          stage.state === INFINITE_HOLD
                            ? null
                            : <div>
                              <p style={{top: "3px", borderBottom: "20px solid #fff"}}
                                 onClick={() => addStep(step, index, index_)}
                              />
                              <p style={{top: "27px", borderTop: "20px solid #fff"}}
                                 onClick={() => removeStep(index, index_)}
                              />
                            </div>
                        }
                      </div>
                    ))
                ))
              }
            </section>
          </div>
        </div>
        <div className="protocolPagePart1">
          <div className="protocolPagePart1Left">
            <header className="componentTitle">
              <div/>
              <div>{isCN ? "参数设置" : "Parameter Setting"}</div>
              {/*<div style={{backgroundPositionY: isChangeLid ? 37 : 0}} title='热盖开关' onClick={changeLidTemp}/>*/}
            </header>
            <ul>
              <li>
                <div>{isCN ? "热盖开关" : "Lid Heating Switch"}</div>
                <div style={{backgroundPositionY: isChangeLid ? 51 : 0}} title="热盖开关" onClick={changeLidTemp}/>
              </li>
              <li>
                <div>{isCN ? "热盖关闭温度" : "Lid Close Temp"}</div>
                <div>
                  <input type="number" defaultValue={30} readOnly={true}/><span>℃</span>
                </div>
              </li>
              <li>
                <div>{isCN ? "热盖温度" : "Cover Temp"}</div>
                <div>
                  <input type="number" defaultValue={data.coverTemp} onBlur={e => {
                    e.target.value = Math.max(60, e.target.value);
                    e.target.value = Math.min(110, e.target.value);
                    setCoverTemp(e.target.value);
                  }}/><span>℃</span>
                </div>
              </li>

              <li>
                <div>{isCN ? "反应体积" : "Reaction Volume"}</div>
                <div>
                  <input type="number" defaultValue={data.reactionVolume} onBlur={e => {
                    e.target.value = Math.max(1, e.target.value);
                    e.target.value = Math.min(125, e.target.value);
                    setReactionVolume(e.target.value);
                  }}/><span>ul</span>
                </div>
              </li>
            </ul>
          </div>
          <div className="protocolPagePart1Right">
            <header className="componentTitle">
              <div/>

              <div>{isCN ? "快速运行" : "Run First Mode"}</div>
              <Link to={"/main/run"} onClick={jump2Run}>
                <div/>
                <div>{isCN ? "运行" : "Go To Run"}</div>
              </Link>
            </header>
            <p>{isCN ? "扫描通道" : "Scan Channel"}</p>
            <ul>
              {
                //TODO:channel未更新
                scanChannel.map((item, index) => (
                  <li key={index}>
                    <div className={item.scan ? "selectedStyle" : ""}
                         onClick={() => selectScanChannel(item, index)}
                    />
                    <Dropdown
                      overlay={
                        <Menu>
                          {
                            item.lists.map(list => (
                              <Menu.Item key={list.name}>
                                {
                                  list.isSelected
                                    ? <div
                                      onClick={() => chooseScanChannel(list, index)}
                                      style={MENU_STYLE}>{list.name}</div>
                                    : <div style={{
                                      ...MENU_STYLE,
                                      color: "#bbb"
                                    }}>{list.name}</div>
                                }
                              </Menu.Item>
                            ))
                          }
                        </Menu>
                      }
                      overlayClassName="antdDropDownStyle"
                      placement="topCenter"
                      trigger={['click']}>
                      <div>{item.lists.some(it => it.name === item.showName && it.isSelected) && item.showName}</div>
                    </Dropdown>
                  </li>
                ))
              }
            </ul>
          </div>
        </div>
      </section>
      {
        showSettingTable
          ? <div className="protocolSettingAlert">
            <header>
              <div>
                <p>{isCN ? "高级设置" : "Advanced Setting"}</p>
                <p onClick={() => setShowSettingTable(false)}/>
              </div>
              <hr/>
            </header>
            <section>
              <div className="protocolSettingAlertTop">
                <div>
                  <p>{isCN ? "温度梯度" : "Gradient"}</p>
                </div>
                <ul>
                  <li>
                    <div>
                      <div onClick={selectSettingGradient}
                           className={gradientSelected ? "selectedStyle" : ""}/>
                      <div style={{width: "300px"}}>{isCN ? "设置温度梯度" : "Setting Gradient Delta Temperature"}</div>
                    </div>
                    <div>{isCN ? "有效范围" : "Valid Range"}: 30℃</div>
                  </li>
                  <li>
                    <div>
                      <span>{isCN ? "第1列" : "Start"}</span>
                      <input ref={e => startTemp = e} type="number" readOnly={!gradientSelected}
                             defaultValue={stages[stepPosition.stageIndex].steps[stepPosition.stepIndex].gradientDeltaTemperature.start}
                             onBlur={gradientSelected ? e => e.target.value = changeGradientTemperature(e.target.value, Number(e.target.value) - 30)[0] : null}
                        // onBlur={gradientSelected ? e => e.target.value = changeGradientTemperature(e.target.value, endTemp.value)[0] : null}
                      />
                      <span>℃</span>
                    </div>
                    <div>
                      <span>{isCN ? "第12列" : "End"}</span>
                      <input ref={e => endTemp = e} type="number" readOnly={!gradientSelected}
                             key={stages[stepPosition.stageIndex].steps[stepPosition.stepIndex].gradientDeltaTemperature.end}
                             defaultValue={stages[stepPosition.stageIndex].steps[stepPosition.stepIndex].gradientDeltaTemperature.end}
                             onBlur={gradientSelected ? e => e.target.value = changeGradientTemperature(startTemp.value, e.target.value)[1] : null}
                      />
                      <span>℃</span>
                    </div>
                  </li>
                  <li>
                    <ul className="protocolSettingColorBar">
                      {
                        temperatureColorBar.map((item, index) => (<li key={index}
                                                                      style={{backgroundColor: item.color}}>{item.value}</li>))
                      }
                    </ul>
                  </li>
                </ul>
              </div>
              <div className="protocolSettingAlertBottom">
                <div>
                  <p>{isCN ? "自动增量设置" : "Auto Delta"}</p>
                </div>
                <ul>
                  <li>
                    <div>
                      <div onClick={selectPauseAfter}
                           className={stages[stepPosition.stageIndex].steps[stepPosition.stepIndex].autoDelta.checkAutoPauseAfter ? "selectedStyle" : ""}
                      />
                      <div>{isCN ? "后置自动暂停" : "Auto Pause After"}</div>
                    </div>
                    <div>{isCN ? "每个循环步骤后自动暂停" : "Pause automatically after each step of the cycle"}</div>
                  </li>
                  <li>
                    <div>
                      <div onClick={selectDeltaTemperature}
                           className={stages[stepPosition.stageIndex].steps[stepPosition.stepIndex].autoDelta.checkAutoDeltaTemperature ? "selectedStyle" : ""}
                      />
                      <div>{isCN ? "自动增量温度" : "Auto Delta Temperature"}</div>
                      <div>+</div>
                      <input type="number"
                             defaultValue={stages[stepPosition.stageIndex].steps[stepPosition.stepIndex].autoDelta.autoDeltaTemperature}
                             onBlur={e => {
                               e.target.value = Math.max(-10, e.target.value);
                               e.target.value = Math.min(10, e.target.value);
                               changeDeltaTemperature(e.target.value);
                             }}
                      />
                      <span>℃</span>
                    </div>
                    <div>{isCN ? "有效温度自动增量范围" : "Valid Range"}: -10 to 10 ℃</div>
                  </li>
                  <li>
                    <div>
                      <div onClick={selectDeltaTime}
                           className={stages[stepPosition.stageIndex].steps[stepPosition.stepIndex].autoDelta.checkAutoDeltaTime ? "selectedStyle" : ""}
                      />
                      <div>{isCN ? "自动增量时间" : "Auto Delta Time"}</div>
                      <div>+</div>
                      <input type="number"
                             defaultValue={stages[stepPosition.stageIndex].steps[stepPosition.stepIndex].autoDelta.autoDeltaTime}
                             onBlur={e => {
                               e.target.value = Math.max(-120, e.target.value);
                               e.target.value = Math.min(120, e.target.value);
                               changeDeltaTime(e.target.value);
                             }}
                      />
                      <span>S</span>
                    </div>
                    <div>{isCN ? "有效时间自动增量范围范围" : "Valid Range"}: -120 to 120 Second</div>
                  </li>
                  <li>
                    <div>
                      <div onClick={selectRampRate}
                           className={stages[stepPosition.stageIndex].steps[stepPosition.stepIndex].autoDelta.checkRampRate ? "selectedStyle" : ""}
                      />
                      <div>{isCN ? "温度速率调节" : "Ramp Rate"}</div>
                      <input type="number"
                             defaultValue={stages[stepPosition.stageIndex].steps[stepPosition.stepIndex].autoDelta.rampRate}
                             onBlur={e => {
                               e.target.value = Math.max(0.1, e.target.value);
                               e.target.value = Math.min(10, e.target.value);
                               changeRampRate(e.target.value);
                             }}
                      />
                      <span>℃</span>
                    </div>
                    <div>{isCN ? "调节范围" : "Valid Range"}: 0.1 to 10 ℃</div>
                  </li>
                </ul>
              </div>
            </section>
          </div>
          : null
      }
    </div>
  );
});
